package cn.onein.edu.web.controller;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import cn.onein.edu.biz.bean.Item;
import cn.onein.edu.biz.bean.Order;
import cn.onein.edu.biz.bean.Product;
import cn.onein.edu.biz.bean.User;
import cn.onein.edu.common.OrderFromType;
import cn.onein.edu.common.OrderStatusType;
import cn.onein.edu.common.PaymentType;
import cn.onein.edu.util.PaymentRequestHandler;
import cn.onein.edu.util.PaymentResponseHandler;
import cn.onein.edu.util.PaymentUtil;
import cn.onein.edu.util.StringUtil;
import cn.onein.edu.web.common.base.BaseController;
import cn.onein.edu.web.service.PaymentService;
import cn.onein.edu.web.vo.OrderVO;
import cn.onein.edu.web.vo.ProductVO;

/**
 * 支付相关的控制器
 * @author Upton
 *
 */
@Controller
public class PaymentController extends BaseController{
	
	Logger logger = Logger.getLogger(PaymentController.class);
	
	@Autowired
	private PaymentService paymentService;
	
	/**
	 * 创建订单跳转页面
	 * @return
	 */
	@RequestMapping(value = "/payment/order.create", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView createOrder(HttpServletRequest req, String pid){
		Map<String, Object> map = new HashMap<String,Object>();
		User user = this.getLoginUser(req);
		
		if(pid == null || "".equals(pid)){
			return new ModelAndView("error");
		}
		
		Product product = paymentService.getProductById(Long.valueOf(pid));
		if(product == null){
			return new ModelAndView("error");
		}
		
		List<ProductVO> vos = new ArrayList<ProductVO>();
		ProductVO vo = new ProductVO();
		vo.setId(product.getId().toString());
		vo.setName(product.getName());
		vo.setPrice(StringUtil.fenToYuan(product.getPrice()));
		vo.setType(product.getType().toString());
		vo.setDescription(product.getDescription());
		vos.add(vo);
		
		//生成订单
		Order order = new Order();
		order.setAmount(product.getPrice());
		order.setOrderDate(new Date());
		order.setOrderFrom(OrderFromType.OfficialWeb);
		order.setOrderNo(PaymentUtil.generateNewOrderNo());
		order.setOrderStatus(OrderStatusType.Create);
		order.setUpdateDate(new Date());
		order.setUserId(user.getId());
		
		Item item = new Item();
		item.setProductId(product.getId());
		item.setAmount(product.getPrice());
		
		try{
			Order createdOrder =  paymentService.insertOrderAndItem(order, item);
			
			String redirectUrl = "redirect:/payment/select.pay?orderNo=" + createdOrder.getOrderNo() + "&orderId=" + createdOrder.getId();

			return new ModelAndView(redirectUrl , map);
		}catch(Exception e){
			logger.error("insert order and item error", e);
			return new ModelAndView("error");
		}
	}
	
	/**
	 * 选择支付方式页面
	 * @return
	 */
	@RequestMapping(value = "/payment/select.pay", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView select(HttpServletRequest req, Long orderId,String orderNo){
		List<Product> products = new ArrayList<Product>();
	    Map<String, Object> param = new HashMap<String, Object>();
	    Order order = null;
	    
	    try{
	    	List<Item> items = paymentService.getItemByOrderId(orderId);
			for(Item item : items){
				Product procduct = paymentService.getProductById(item.getProductId());
				products.add(procduct);
			}
			
		   order = paymentService.getOrderByOrderNo(orderNo);
	    }catch(Exception e){
	    	logger.error("order pay error", e);
	    }
	    
		param.put("products", convertProductVO(products));
		param.put("order", convertOrderVO(order));
		
		this.setMenu(param, MENU_VALUE_PAYMENT);

		return new ModelAndView("payment/select", param);
	}
	
	/**
	 * 执行指定方式的支付
	 * @return
	 * @throws IOException 
	 */
	@RequestMapping(value = "/payment/apply.pay", method = { RequestMethod.GET, RequestMethod.POST })
	public void apply(HttpServletRequest req,HttpServletResponse resp,String paymentType,String oNo) throws IOException{
		PaymentType payment_Type = null;
		Order order = null;
		Product product = null;
		String URL = "";
		String notifyUrl = "";
		String resultUrl = "";
		String clientIP = req.getRemoteAddr();
		
		if(oNo == null || "".equals(oNo) || paymentType == null || "".equals(paymentType)){
			return ;
		}
		
		try{
			payment_Type = PaymentType.valueOf(paymentType);
			
			order = paymentService.getOrderByOrderNo(oNo);
			if(order == null){
				return ;
			}
			List<Item> items = paymentService.getItemByOrderId(order.getId());
			for(Item item : items){
				product = paymentService.getProductById(item.getProductId());
			}
		}catch(Exception e){
			logger.error("Get order error in apply.",e);
		}

		if(product == null){
			return;
		}
		
		if(PaymentType.Tenpay == payment_Type){
			// 财付通
			notifyUrl = req.getRequestURL().toString().replace("apply.pay", "tenpay.notify");
			resultUrl = req.getRequestURL().toString().replace("apply.pay", "tenpay.result");
			URL = this.tenpayURL(order.getAmount().toString(), product.getDescription(), notifyUrl, order.getOrderNo(),resultUrl,clientIP);
		}else if(PaymentType.Alipay == payment_Type){
			// 支付宝
			notifyUrl = req.getRequestURL().toString().replace("apply.pay", "alipay.notify");
			resultUrl = req.getRequestURL().toString().replace("apply.pay", "alipay.result");
			URL= this.alipayURL(order.getOrderNo(), product.getName(), product.getDescription(), order.getAmount().toString(),notifyUrl,resultUrl);
		}else if(PaymentType.Cmpay == payment_Type){
			// 手机支付
			
		}
		
		resp.sendRedirect(URL);
	}
	
	/**
	 *  财付通通知URL，没有返回页面
	 * @throws IOException 
	 */
	@RequestMapping(value = "/payment/tenpay.notify", method = { RequestMethod.GET, RequestMethod.POST })
	public void tenpayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException{
		logger.debug("URL:"+request.getRequestURL());
		
		logger.debug("1.财付通回调通知开始执行--------------------------");
		PaymentResponseHandler resHandler = PaymentResponseHandler.getInstance(PaymentType.Tenpay,request);
		logger.debug("2.财付通初始化resHandler成功--------------------------");
		if(resHandler.isPaySign()) {
			logger.debug("3.财付通签名验证正确--------------------------");
			//交易单号
			String transaction_id = resHandler.getParam("transaction_id");
			//订单号
			String orderNo = resHandler.getParam("out_trade_no");
			
			//支付结果
			String trade_state = resHandler.getParam("trade_state");
			
			//通知Id
			String notify_id = resHandler.getParam("notify_id");
			
			//支付完成时间
			String time_end = resHandler.getParam("time_end");
			logger.debug("4.财付通回调参数读取成功--------------------------");
			if("0".equals(trade_state) ) {
				logger.debug("5.财付通支付成功，开始修改订单状态--------------------------");
				this.doOrderSuccess(orderNo, transaction_id,PaymentType.Tenpay);
				response.getWriter().write("success");
				logger.debug("6.财付通订单状态修改成功--------------------------");
			} else {
				logger.debug("7.财付通支付失败--------------------------");
				logger.error(resHandler.getParam("pay_info"));
				response.getWriter().write("fail");
			}
		} else {
			logger.debug("8.财付通签名验证失败--------------------------");
			logger.debug(resHandler.getDebugInfo());
			response.getWriter().write("fail");
		}
		
	}
	
	/**
	 *  支付宝通知URL，没有返回页面
	 * @throws IOException 
	 */
	@RequestMapping(value = "/payment/alipay.notify", method = { RequestMethod.GET, RequestMethod.POST })
	public void alipayNotify(HttpServletRequest request, HttpServletResponse response) throws IOException{
		logger.debug("1.支付宝回调通知开始执行--------------------------");
		PaymentResponseHandler resHandler = PaymentResponseHandler.getInstance(PaymentType.Alipay,request);
		logger.debug("2.支付宝初始化resHandler成功--------------------------");
		if(resHandler.isPaySign()) {
			logger.debug("3.支付宝签名验证正确--------------------------");
			//交易单号
			String transaction_id = resHandler.getParam("trade_no");
			//订单号
			String orderNo = resHandler.getParam("out_trade_no");
			
			//支付结果
			String trade_state = resHandler.getParam("trade_status");
			
			//通知Id
			String notify_id = resHandler.getParam("notify_id");
			
			//支付完成时间
			String time_end = resHandler.getParam("notify_time");
			logger.debug("4.支付宝回调参数读取成功--------------------------");
			if(trade_state.equals("TRADE_FINISHED") || trade_state.equals("TRADE_SUCCESS") ) {
				logger.debug("5.支付宝支付成功，开始修改订单状态--------------------------");
				this.doOrderSuccess(orderNo, transaction_id,PaymentType.Alipay);
				response.getWriter().write("success");
				logger.debug("6.支付宝订单状态修改成功--------------------------");
			} else {
				logger.debug("7.支付宝支付失败--------------------------");
				logger.error(resHandler.getParam("pay_info"));
				response.getWriter().write("fail");
			}
		} else {
			logger.debug("8.支付宝签名验证失败--------------------------");
			logger.error(resHandler.getParam("pay_info"));
			response.getWriter().write("fail");
		}
	}
	
	/**
	 * 财付通支付结果显示
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/payment/tenpay.result", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView tenpayResult(HttpServletRequest request,HttpServletResponse response){
		logger.debug("1.财付通支付结果开始执行--------------------------");
		Map<String, Object> param = new HashMap<String,Object>();
		
		PaymentResponseHandler resHandler = PaymentResponseHandler.getInstance(PaymentType.Tenpay,request);
		
		this.doPayResult(resHandler, param);
		
		this.setMenu(param, MENU_VALUE_PAYMENT);
		
		return new ModelAndView("payment/result", param);
	}
	
	/**
	 * 支付宝结果显示
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/payment/alipay.result", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView alipayResult(HttpServletRequest request,HttpServletResponse response){
		logger.debug("1.支付宝支付结果开始执行--------------------------");
        Map<String, Object> param = new HashMap<String,Object>();
		
		PaymentResponseHandler resHandler = PaymentResponseHandler.getInstance(PaymentType.Alipay,request);
		
		this.doPayResult(resHandler, param);
		
		this.setMenu(param, MENU_VALUE_PAYMENT);
		
		return new ModelAndView("payment/result", param);
	}
	
	/**
	 * 直接进入结果页面
	 * @param request
	 * @param response
	 * @return
	 */
	@RequestMapping(value = "/payment/result", method = { RequestMethod.GET, RequestMethod.POST })
	public ModelAndView result(HttpServletRequest request,HttpServletResponse response){
		Map<String, Object> param = new HashMap<String, Object>();
		Order order = null;
		
		User user = (User)request.getSession(true).getAttribute(SESSION_USER_KEY);
		if(null == user){
			return new ModelAndView("error");
		}
		
		try{
			order = paymentService.getLastOrderByUserId(user.getId());
		}catch(Exception e){
			logger.error("Register step3 error.", e);
			return new ModelAndView("error");
		}
		
        param.put("order", order == null ? null : convertOrderVO(order));
        this.setMenu(param, MENU_VALUE_PAYMENT);
        
		return new ModelAndView("payment/result",param);
	}
	
	/**
	 * 处理支付结果
	 * @param resHandler
	 * @param param
	 */
	private void doPayResult(PaymentResponseHandler resHandler,Map<String,Object> param){
		List<Product> products = new ArrayList<Product>();
		Order order = null;
		
		if(resHandler.isPaySign()) {
			logger.debug("2.支付结果签名正确--------------------------");
			//订单号
			String orderNo = resHandler.getParam("out_trade_no");
			logger.debug("3.支付结果读取参数正确--------------------------");
			try{
				order = paymentService.getOrderByOrderNo(orderNo);
				if(order == null){
					logger.error("Order is null error in tenpyResult.");
					return;
				}
				
				List<Item> items = paymentService.getItemByOrderId(order.getId());
				for(Item item : items){
					Product product = paymentService.getProductById(item.getProductId());
					products.add(product);
				}
			}catch(Exception e){
				logger.debug("4.支付结果取得订单错误--------------------------");
				logger.error("GET order error in tenpyResult.",e);
				return;
			}
		}else{
			logger.debug("5.支付结果签名失败--------------------------");
			logger.error(resHandler.getParam("pay_info"));
		}
		
		param.put("order", convertOrderVO(order));
		param.put("products", convertProductVO(products));
	}
	
   /**
    * 财付通支付请求
    * @param total_fee 订单金额
    * @param body 订单描述
    * @param notifyUrl 通知URL
    * @param orderNo 商品订单
    * @param returnUrl 支付结果URL
    * @param clientIP 用户IP
    * @return
    * @throws UnsupportedEncodingException
    */
	private String tenpayURL(String total_fee,String body,String notifyUrl,String orderNo,String returnUrl,String clientIP) throws UnsupportedEncodingException{
		PaymentRequestHandler handler = PaymentRequestHandler.getInstance(PaymentType.Tenpay);
		
		handler.setParam("input_charset", "UTF-8");
		handler.setParam("body", body);
		handler.setParam("return_url", returnUrl);
		handler.setParam("notify_url", notifyUrl);
		handler.setParam("out_trade_no", orderNo);
		handler.setParam("total_fee", total_fee);
		handler.setParam("fee_type", "1");
		handler.setParam("spbill_create_ip", clientIP);

		return handler.getRequestURL();
	}
	/**
	 * 支付宝支付请求
	 * @param orderNo 商品订单号
	 * @param subject 商品名称
	 * @param body 产品描述
	 * @param total_fee 订单金额
	 * @param notifyUrl 通知URL
	 * @param returnUrl 支付结果URL
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	private String alipayURL(String orderNo,String subject,String body,String total_fee,String notifyUrl,String returnUrl) throws UnsupportedEncodingException{
		PaymentRequestHandler handler = PaymentRequestHandler.getInstance(PaymentType.Alipay);
		
		handler.setParam("service","create_direct_pay_by_user");
		handler.setParam("payment_type","1");
		handler.setParam("return_url", returnUrl);
		handler.setParam("notify_url", notifyUrl);
		handler.setParam("show_url", "");
		handler.setParam("out_trade_no", orderNo);
		handler.setParam("subject", subject);
		handler.setParam("body", body);
		handler.setParam("total_fee", total_fee);
		
		return handler.getRequestURL();
	}
	
	/**
	 * 处理订单成功
	 * @param orderNo
	 * @param payNo
	 */
	private void doOrderSuccess(String orderNo,String payNo,PaymentType paymentType){
		Order order = null;
		
		try{
			order = paymentService.getOrderByOrderNo(orderNo);
			if(order != null && order.getOrderStatus() == OrderStatusType.Create){
				paymentService.orderSuccessByOrderNo(orderNo, payNo,paymentType);
			}
		}catch(Exception e){
			logger.error("Get order error in doOrdersuccess",e);
		}
	}
	
	private OrderVO convertOrderVO(Order order){
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		
		OrderVO vo = new OrderVO();
		vo.setId(order.getId());
		vo.setAmount(StringUtil.fenToYuan(order.getAmount()));
		vo.setOrderDate(df.format(order.getOrderDate()));
		vo.setOrderNo(order.getOrderNo());
		vo.setOrderStatus(order.getOrderStatus() == null ? "&nbsp; " : order.getOrderStatus().toString());
		vo.setPaymentType(order.getPaymentType() == null ? " &nbsp;" : order.getPaymentType().toString());
	    vo.setOrderFrom(order.getOrderFrom() == null ? "&nbsp;" : order.getOrderFrom().toString());
	    
	    return vo;
	}
	
	private List<ProductVO> convertProductVO(List<Product> products){
		List<ProductVO> vos = new ArrayList<ProductVO>();
		for (Product o : products) {
			ProductVO vo = new ProductVO();
			vo.setId(o.getId().toString());
			vo.setName(o.getName());
			vo.setPrice(StringUtil.fenToYuan(o.getPrice()));
			vo.setDescription(o.getDescription());
			vo.setType(o.getType().toString());
			vos.add(vo);
		}
		return vos;
	}
}
